﻿#region zh-CHS 2010 - 2010 DemoSoft 团队 | en 2010-2010 DemoSoft Team

//     NOTES
// ---------------
//
// This file is a part of the MMOCE(Massively Multiplayer Online Client Engine) for .NET.
//
//                              2010-2010 DemoSoft Team
//
//
// First Version : by H.Q.Cai - mailto:caihuanqing@hotmail.com

/***************************************************************************
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 ***************************************************************************/

#region zh-CHS 包含名字空间 | en Include namespace
using System;
using System.Threading;
using Demo.Silverlight.Core.Common.Atom;
using Demo.Silverlight.Core.Entity.Character;


#endregion

namespace Demo.Silverlight.Core.Network
{
    /// <summary>
    /// 网络的主状态,每个连接都会产生新的NetState
    /// </summary>
    public sealed partial class NetState : IDisposable
    {
        #region zh-CHS 构造和初始化和清理 | en Constructors and Initializers and Dispose
        /// <summary>
        /// 有实例产生时调用
        /// </summary>
        /// <param name="clientSocket"></param>
        /// <param name="messagePump"></param>
        internal NetState( Connecter connecter )
        {
            if ( connecter == null )
                throw new ArgumentNullException( "connecter", "NetState.NetState(...) - connecter == null error!" );

            m_Connecter = connecter;
            m_ConnectedOn = DateTime.Now;
            //m_ToString = connecter.Socket.AddressFamily.ToString();
        }
        #endregion

        #region zh-CHS 共有属性 | en Public Properties
        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 客户开始连接的时间
        /// </summary>
        private DateTime m_ConnectedOn = DateTime.Now;
        #endregion
        /// <summary>
        /// 客户开始连接的时间
        /// </summary>
        public DateTime ConnectedOn
        {
            get { return m_ConnectedOn; }
        }

        /// <summary>
        /// 客户总共连接的时间
        /// </summary>
        public TimeSpan ConnectedFor
        {
            get { return ( DateTime.Now - m_ConnectedOn ); }
        }

        //#region zh-CHS 私有成员变量 | en Private Member Variables
        ///// <summary>
        ///// 加解密的数据包
        ///// </summary>
        //private IPacketEncoder m_Encoder;
        //#endregion
        ///// <summary>
        ///// 加解密的数据包接口
        ///// </summary>
        //public IPacketEncoder PacketEncoder
        //{
        //    get { return m_Encoder; }
        //    set { m_Encoder = value; }
        //}

        /// <summary>
        /// 客户是否在运行, 如果没有表示已经断开了连接
        /// </summary>
        public bool Running
        {
            get { return m_Connecter.IsConnected; }
        }

        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 网络句柄
        /// </summary>
        private Connecter m_Connecter = null;
        #endregion
        /// <summary>
        /// 客户端连接的句柄
        /// </summary>
        public Connecter NetSocket
        {
            get { return m_Connecter; }
        }

        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 
        /// </summary>
        private ReceiveQueue m_ReceiveQueue = new ReceiveQueue();
        #endregion
        /// <summary>
        /// 接收到的环形缓冲区
        /// </summary>
        public ReceiveQueue ReceiveBuffer
        {
            get { return m_ReceiveQueue; }
        }

        /// <summary>
        /// 缓冲区内还有多少没有发送的数据
        /// </summary>
        public long WaitSendSize
        {
            get { return m_SendQueue.WaitSendSize; }
        }

        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 人物
        /// </summary>
        private CharacterBase m_Player = null;
        #endregion
        /// <summary>
        /// 人物
        /// </summary>
        public CharacterBase Player
        {
            get { return m_Player; }
            set { m_Player = value; }
        }
        #endregion

        #region zh-CHS 内部属性 | en Internal Properties

        #region zh-CHS 内部SendQueue属性 | en Internal SendQueue Properties
        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 发送数据的集合
        /// </summary>
        private SendQueue m_SendQueue = new SendQueue();
        #endregion
        /// <summary>
        /// 发送数据的集合
        /// </summary>
        internal SendQueue SendQueue
        {
            get { return m_SendQueue; }
        }
        #endregion

        #endregion

        #region zh-CHS 共有方法 | en public Method
        /// <summary>
        /// 发送数据(在多线程中主要实现了顺序的发送)
        /// </summary>
        /// <param name="packet">需要发送的数据包</param>
        public void Send( Packet packet )
        {
            if ( this.Running == false )
                return;

            Monitor.Enter( this );
            try
            {
                this.InternalSendInLock( packet );
            }
            finally
            {
                Monitor.Exit( this );
            }

            // 如果没有错误且需要等待发送，则放在全局的处理中。。。
            if ( m_SendQueue.IsEmpty == false )
                this.OnFlush();
        }

        /// <summary>
        /// 清理当前的网络数据,并断开连接(Flush == true 则默认5秒以后断开)
        /// </summary>
        /// <param name="bFlush"></param>
        public void Dispose()
        {
            if ( this.NetSocket.IsConnected == true )
                m_Connecter.Dispose();
        }
        #endregion

        #region zh-CHS 内部方法 | en Internal Methods
        /// <summary>
        /// 开始运行客户端的处理
        /// </summary>
        internal void OnStart()
        {
            // 设置NetState(需位于Start(...)函数之前)，检查是否已断开与已收到新数据。
            m_Connecter.NetState = this;

            // 连接的通知事件
            EventHandler<NetStateConnectEventArgs> tempEvent = m_EventConnect;
            if ( tempEvent != null )
            {
                NetStateConnectEventArgs netStateConnectEventArgs = new NetStateConnectEventArgs( this );
                tempEvent( this, netStateConnectEventArgs );
            }
        }

        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 发送数据的锁
        /// </summary>
        LockInOut m_LockFlush = new LockInOut( false );
        #endregion
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        internal bool OnFlush()
        {
            if ( m_SendQueue.IsEmpty == true )
                return true;

            if ( this.Running == false )
                return false;

            // 防止发送的顺序出错
            if ( m_LockFlush.InLock() == false )
                return false;

            SendBuffer sendBuffer = m_SendQueue.Dequeue();
            while ( sendBuffer.IsNull == false )
            {
                m_Connecter.SendBuffer( sendBuffer.Buffer, 0, (int)sendBuffer.Length );

                // 释放数据
                sendBuffer.Release();

                // 需添加检测是否还有数据 否则以后就发不出去数据了（该问题解决）
                sendBuffer = m_SendQueue.Dequeue();
            }

            m_LockFlush.OutLock();

            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="RecvMessageBlock"></param>
        internal void OnReceive( byte[] buffer, int office, int size )
        {
            if ( this.Running == false )
                return;

            // 放入环绕缓冲区
            m_ReceiveQueue.Enqueue( buffer, office, size );
        }

        /// <summary>
        /// 调用ClientSocketHandler.CloseSocket(...)的时候会产生此调用
        /// </summary>
        internal void OnDisconnect()
        {
            // 如果还存在需要发送的数据,则直接清空
            if ( m_SendQueue.IsEmpty == false )
                m_SendQueue.Clear(); // 内部已经有锁定

            // 断开的通知事件
            EventHandler<NetStateDisconnectEventArgs> tempEvent = m_EventDisconnect;
            if ( tempEvent != null )
            {
                NetStateDisconnectEventArgs netStateDisconnectEventArgs = new NetStateDisconnectEventArgs( this );
                tempEvent( this, netStateDisconnectEventArgs );
            }
        }
        #endregion

        #region zh-CHS 私有方法 | en Private Methods
        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="packet">需要发送的数据包</param>
        private void InternalSendInLock( Packet packet )
        {
            if ( this.Running == false )
            {
                // 表示已处理发送
                packet.Release();
                return;
            }

            // 连接的通知事件
            EventHandler<NetStateSendPacketEventArgs> tempEvent = m_EventSendPacket;
            if ( tempEvent != null )
            {
                NetStateSendPacketEventArgs sendEventArgs = new NetStateSendPacketEventArgs( this, packet );
                tempEvent( this, sendEventArgs );

                if ( sendEventArgs.IsCancelSend == true )
                {
                    // 表示已处理发送
                    packet.Release();
                    return;
                }
            }

            PacketBuffer packetBuffer = packet.AcquireBuffer();
            if ( packetBuffer.IsNULL == true )
                throw new Exception( "NetState.InternalSend(...) - packetBuffer.IsNULL == true error!" );

            byte[] byteBuffer = packetBuffer.Buffer;
            long lLength = packetBuffer.Length;

            // 加密数据
            //if ( m_Encoder != null )
            //    m_Encoder.EncodeOutgoingPacket( this, ref byteBuffer, ref lLength );

            m_SendQueue.Enqueue( byteBuffer, 0, lLength );

            // 表示已处理发送
            packet.Release();
        }
        #endregion

        #region zh-CHS 方法覆盖 | en Override Methods
        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 当前实例的IP地址字符串
        /// </summary>
        private string m_ToString = string.Empty;
        #endregion
        /// <summary>
        /// 当前实例的IP地址字符串
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return m_ToString;
        }
        #endregion

        #region zh-CHS 共有事件 | en Public Event
        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 
        /// </summary>
        private EventHandler<NetStateConnectEventArgs> m_EventConnect;
        #endregion
        /// <summary>
        /// 当网络连接时调用
        /// </summary>
        public event EventHandler<NetStateConnectEventArgs> EventConnect
        {
            add
            {
                Monitor.Enter( this );
                try
                {
                    m_EventConnect += value;
                }
                finally
                {
                    Monitor.Exit( this );
                }
            }
            remove
            {
                Monitor.Enter( this );
                try
                {
                    m_EventConnect -= value;
                }
                finally
                {
                    Monitor.Exit( this );
                }
            }
        }

        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 
        /// </summary>
        private EventHandler<NetStateDisconnectEventArgs> m_EventDisconnect;
        #endregion
        /// <summary>
        /// 当网络断开时调用
        /// </summary>
        public event EventHandler<NetStateDisconnectEventArgs> EventDisconnect
        {
            add
            {
                Monitor.Enter( this );
                try
                {
                    m_EventDisconnect += value;
                }
                finally
                {
                    Monitor.Exit( this );
                }
            }
            remove
            {
                Monitor.Enter( this );
                try
                {
                    m_EventDisconnect -= value;
                }
                finally
                {
                    Monitor.Exit( this );
                }
            }
        }

        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 
        /// </summary>
        private EventHandler<NetStateSendPacketEventArgs> m_EventSendPacket;
        #endregion
        /// <summary>
        /// 
        /// </summary>
        public event EventHandler<NetStateSendPacketEventArgs> EventSendPacket
        {
            add
            {
                Monitor.Enter( this );
                try
                {
                    m_EventSendPacket += value;
                }
                finally
                {
                    Monitor.Exit( this );
                }
            }
            remove
            {
                Monitor.Enter( this );
                try
                {
                    m_EventSendPacket -= value;
                }
                finally
                {
                    Monitor.Exit( this );
                }
            }
        }
        #endregion
    }
}
#endregion

